package com.atguigu.spring;

import com.atguigu.spring.demo02.Demo02Cmp;
import com.atguigu.spring.demo04.controller.StuController;
import com.atguigu.spring.demo04.dao.StuDao;
import com.atguigu.spring.demo04.service.impl.StuServiceImpl;
import com.atguigu.spring.demo08.DogController;
import com.atguigu.spring.demo08.DogService;
import com.atguigu.spring.demo09.BananaController;
import com.atguigu.spring.demo10.OrangeController;
import com.atguigu.spring.demo11.Demo11Controller;
import com.atguigu.spring.demo12.Demo12Component;
import com.atguigu.spring.demo13.Demo13Component;
import com.atguigu.spring.demo14.Demo14Component;
import com.atguigu.spring.demo17.Demo17MachineFactory;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.slf4j.LoggerFactoryFriend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootApplication

// 一旦自定义包扫描范围，那么默认扫描的范围就会失效
// @ComponentScan("com.flower.spring.demo02")
public class Module19MainType {

    public static void main(String[] args) throws SQLException {
        // 1、启动 SpringBoot 程序，返回 IoC 容器对象
        ConfigurableApplicationContext ioc = SpringApplication.run(Module19MainType.class, args);
        System.out.println(ioc);

        System.out.println("----------------------------------------------------");

        // 2、获取当前 IoC 容器中所有 Bean 的名称
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }

        System.out.println("----------------------------------------------------");

        // 3、实验03：从 IoC 容器中获取 bean 对象的引用
        // [1]获取方式一：根据 bean 的 id 名称获取，返回的类型是 Object
        Demo02Cmp demo02Cmp01 = (Demo02Cmp) ioc.getBean("JapaneseGoDie~~~Demo02Cmp");
        System.out.println("demo02Cmp01 = " + demo02Cmp01);
        demo02Cmp01.sayHello();

        // [2]获取方式二：根据 bean 自身的类型获取
        // ※隐患：如果指定的类型在 IoC 容器中能够找到多个匹配的对象，就会抛出如下异常：
        // NoUniqueBeanDefinitionException: No qualifying bean of type 'com.atguigu.spring.demo02.Demo02Cmp' available: expected single matching bean but found 2: JapaneseGoDie~~~Demo02Cmp,demo02CmpSon
        // Demo02Cmp demo02Cmp02 = ioc.getBean(Demo02Cmp.class);
        // System.out.println("demo02Cmp02 = " + demo02Cmp02);
        // demo02Cmp02.sayHello();

        // [3]获取方式三：同时指定 bean 的类型和 id
        Demo02Cmp demo02CmpSon = ioc.getBean("demo02CmpSon", Demo02Cmp.class);
        System.out.println("demo02CmpSon = " + demo02CmpSon);

        System.out.println("----------------------------------------------------");

        // 4、实验04：获取分层注解标记的 bean
        StuController stuController = ioc.getBean(StuController.class);
        System.out.println("stuController = " + stuController);

        StuServiceImpl stuService = ioc.getBean(StuServiceImpl.class);
        System.out.println("stuService = " + stuService);

        StuDao stuDao = ioc.getBean(StuDao.class);
        System.out.println("stuDao = " + stuDao);

        System.out.println("----------------------------------------------------");
        // 5、实验05：测试自动装配（基于 @Autowired）
        stuController.showMessage();

        System.out.println("----------------------------------------------------");
        // 实验08：测试使用 @Resource 注解实现自动装配
        DogController dogController = ioc.getBean(DogController.class);
        DogService dogService = dogController.getDogService();
        System.out.println("dogService = " + dogService);

        System.out.println("----------------------------------------------------");
        // 实验09：测试构造器注入
        BananaController bananaController = ioc.getBean(BananaController.class);
        bananaController.doSth();

        System.out.println("----------------------------------------------------");

        // 实验10：测试 setter 方法注入
        OrangeController orangeController = ioc.getBean(OrangeController.class);
        orangeController.doSth();

        System.out.println("----------------------------------------------------");
        // 实验11：读取外部属性文件
        Demo11Controller demo11Controller = ioc.getBean(Demo11Controller.class);
        demo11Controller.printMessage();

        System.out.println("----------------------------------------------------");

        // 实验12：条件注解
        Demo12Component demo12Component = ioc.getBean(Demo12Component.class);
        System.out.println("demo12Component = " + demo12Component);

        System.out.println("----------------------------------------------------");

        // 实验13：bean 的作用域
        Demo13Component demo13Component01 = ioc.getBean(Demo13Component.class);
        System.out.println("demo13Component01 = " + demo13Component01);

        Demo13Component demo13Component02 = ioc.getBean(Demo13Component.class);
        System.out.println("demo13Component02 = " + demo13Component02);
        System.out.println(demo13Component01 == demo13Component02);

        System.out.println("----------------------------------------------------");

        // 实验14：@Lazy 注解
        Demo14Component demo14Component01 = ioc.getBean(Demo14Component.class);
        Demo14Component demo14Component02 = ioc.getBean(Demo14Component.class);
        System.out.println("demo14Component02 = " + demo14Component02);
        System.out.println("demo14Component02 = " + demo14Component02);
        System.out.println(demo14Component01 == demo14Component02);

        System.out.println("----------------------------------------------------");

        // 实验15：@Bean 注解的用法
//        DataSource dataSource = ioc.getBean(DataSource.class);
//        Connection connection = dataSource.getConnection();
//        System.out.println("connection = " + connection);
//
//        QueryRunner queryRunner = ioc.getBean(QueryRunner.class);
//
//        String sql = "delete from t_tiger where tiger_id=?";
//        queryRunner.update(sql, 10014);

        System.out.println("----------------------------------------------------");

        // 实验16：@Import 注解
        LoggerFactoryFriend friend = ioc.getBean(LoggerFactoryFriend.class);
        System.out.println("friend = " + friend);

        System.out.println("----------------------------------------------------");

        // 实验17：FactoryBean
        Object bean = ioc.getBean("machineFactory");

        // 从 IoC 容器中获取到的是工厂生产的产品：getObject() 方法的返回值，而不是工厂本身
        System.out.println("bean = " + bean);
        System.out.println(bean.getClass().getName());


        System.out.println("----------------------------------------------------");

        // 实验18：测试 @Profile 注解
        DataSource dataSource = ioc.getBean(DataSource.class);
        QueryRunner queryRunner = new QueryRunner(dataSource);
        String sql = "select tiger_name from t_tiger where tiger_id=?";
        Object tigerName = queryRunner.query(sql, new ScalarHandler<>(), 2);
        System.out.println("tigerName = " + tigerName);
    }

}
